package com.itms.tool;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout.LayoutParams;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.itms.tool.data.Image;
import com.itms.tool.data.Object;
import com.itms.tool.utils.ImageFetcher;
import com.j256.ormlite.dao.RuntimeExceptionDao;

public class ImageGridFragment extends ObjectFragment {

	private static final String SELECTION_COUNT = "selection_count";

	private static final String TAG = "ImageGridFragment";

	private static final String NEW_IMAGE_PATH = "new_image_path";
	private static final int NEW_IMAGE_REQUEST_CODE = 17;
	private static final int MENU_ITEM_NEW_IMAGE = 1;
	
	private ImageAdapter mAdapter;
	private GridView mGridView;
	private ImageFetcher mImageFetcher;
	private int mItemSize = 200;

	private Menu mSelectionMenu;
	private int mSelectionInitiatorPosition = -1;
	private int mSelectionCount;
	private boolean mInitialized;
	private Image mPendingImage;
	private String mNewImagePath;

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		setHasOptionsMenu(true);
		if (savedInstanceState != null) {
			mNewImagePath = savedInstanceState.getString(NEW_IMAGE_PATH);
			mSelectionCount = savedInstanceState.getInt(SELECTION_COUNT);
		}
		mGridView = new GridView(getActivity());
		mAdapter = new ImageAdapter(getActivity());
		mImageFetcher = new ImageFetcher(getActivity(), getFragmentManager());
		mImageFetcher.setLoadingBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.empty_photo));
		mImageFetcher.setSize(mItemSize);
		mGridView.setVerticalSpacing(2);
		mGridView.setHorizontalSpacing(2);
		mGridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
		mGridView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

					@Override
					public void onGlobalLayout() {
						mGridView.setNumColumns(mGridView.getWidth() / mItemSize);
						mGridView.setColumnWidth(mItemSize);
					}
				});
		mGridView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				if (isImageSelectionModeEnabled()) {
					toggleImageSelection(position);
				} else {
					Image image = mAdapter.getItem(position);
					startActivity(new Intent()
					.setAction(Intent.ACTION_VIEW)
					.setDataAndType(Uri.fromFile(new File(image.getPath())), "image/*"));
				}
			}
		});
		mGridView.setOnItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
				if (!isImageSelectionModeEnabled()) {
					setImageSelectionModeEnabled(true);
					// remember here position and select
					// it when optionsMenu is re-inflated
					mSelectionInitiatorPosition = position;
				} else {
					toggleImageSelection(position);
				}
				return true;
			}
		});
		mGridView.setAdapter(mAdapter);
		return mGridView;
	}

	@Override
	protected void initContentView(Object object, Bundle savedInstanceState) {
		List<Image> images = object.getImageList();
		mAdapter.addAll(images);
		if (mPendingImage != null) {
			mAdapter.add(mPendingImage);
			mPendingImage = null;
		}
		mInitialized = true;
	}
	
	@Override
	protected void saveObject(Object object) {
		RuntimeExceptionDao<Image, Integer> imgDao = getHelper().getImageDao();
		List<Image> deletedImages = mAdapter.getDeletedImages();
		for (Image img : deletedImages) {
			img.setObject(null);
			imgDao.update(img);
		}
		List<Image> images = mAdapter.getImages();
		for (Image img : images) {
			imgDao.createOrUpdate(img);
		}
	}
	
	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		if (isImageSelectionModeEnabled()) {
			inflater.inflate(R.menu.image_selection, menu);
			mSelectionMenu = menu;
			if (mSelectionInitiatorPosition != -1) {
				// select initially saved position
				setImageSelected(mSelectionInitiatorPosition, true);
			}
			updateSelectionCountTitle();
		} else {
			if (mSelectionMenu != null) {
				// if selection menu before was inflated
				clearSelection();
			}
			menu.add(0, MENU_ITEM_NEW_IMAGE, 102, getString(R.string.camera))
			.setIcon(android.R.drawable.ic_menu_camera)
			.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
			mSelectionMenu = null;
		}
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case MENU_ITEM_NEW_IMAGE:
			takeNewImage();
			return true;
		case R.id.delete_selection:
			mAdapter.deleteSelection();
			setImageSelectionModeEnabled(false);
			return true;
		case R.id.select_all:
			mSelectionCount = mAdapter.getCount();
			mAdapter.selectAll();
			updateSelectionCountTitle();
			return true;
		case R.id.clear_selection:
			setImageSelectionModeEnabled(false);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
	
	public boolean isImageSelectionModeEnabled() {
		return getNewObjectActivity().isImageSelectionModeEnabled();
	}
	
	public void setImageSelectionModeEnabled(boolean value) {
		getNewObjectActivity().setImageSelectionModeEnabled(value);
	}
	
	private void toggleImageSelection(int position) {
		setImageSelected(position, !mAdapter.isItemSelected(position));
	}
	
	private void setImageSelected(int position, boolean selected) {
		if (selected) {
			mSelectionCount++;
		} else {
			mSelectionCount--;
		}
		mAdapter.setItemSelected(position, selected);
		updateSelectionCountTitle();
	}
	
	private void updateSelectionCountTitle() {
		MenuItem title = mSelectionMenu.findItem(R.id.selection_count);
		if (title != null) {
			String selectionCountTitle = getString(R.string.selection_count, mSelectionCount);
			title.setTitle(selectionCountTitle);
		}
	}
	
	public void clearSelection() {
		mAdapter.clearSelection();
		mSelectionCount = 0;
		updateSelectionCountTitle();
	}
	
	private void takeNewImage() {
		String extPicsDir = getExternalPicturesDir();
		if (extPicsDir == null) {
			toast(R.string.external_storage_unavailable);
			return;
		}
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
		mNewImagePath = prepareImageFile(extPicsDir);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mNewImagePath)));
		startActivityForResult(intent, NEW_IMAGE_REQUEST_CODE);
	}

	private String prepareImageFile(String dir) {
		SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
		String path = dir + "/image_" + df.format(new Date()) + ".jpg";
		File file = new File(path);
		try {
			if (!file.createNewFile()) {
				Log.w(TAG, "file: " + path + " already exists, possibly overwriting old data");
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return file.getAbsolutePath();
	}

	private String getExternalPicturesDir() {
		String storageState = Environment.getExternalStorageState();
		Log.v(TAG, "storage state: " + storageState);
		File dir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
		return dir == null ? null : dir.getAbsolutePath();
	}
	
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == Activity.RESULT_OK && requestCode == NEW_IMAGE_REQUEST_CODE) {
			Image image = new Image(mNewImagePath, new Date(), getObject());
			if (mInitialized) {
				mAdapter.add(image);
			} else {
				mPendingImage = image;
			}
		}
	}
	
	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putString(NEW_IMAGE_PATH, mNewImagePath);
		outState.putInt(SELECTION_COUNT, mSelectionCount);
	}
	
	class ImageAdapter extends BaseAdapter {
		
		private Context mContext;
		private List<Image> mImages = new ArrayList<Image>();
		private List<Image> mDeletedImages = new ArrayList<Image>();
		private int mMatchParent = LayoutParams.MATCH_PARENT;
		private boolean mNotifyChange = true;
		
		public ImageAdapter(Context context) {
			mContext = context;
		}

		@Override
		public void notifyDataSetChanged() {
			if (mNotifyChange) super.notifyDataSetChanged();
		}
		
		public List<Image> getImages() {
			return mImages;
		}
		
		public List<Image> getDeletedImages() {
			return mDeletedImages;
		}
		
		public void delete(int position) {
			Image image = mImages.get(position);
			mDeletedImages.add(image);
			mImages.remove(position);
			notifyDataSetChanged();
		}
		
		public void deleteSelection() {
			for (int i = 0; i < mImages.size(); ) {
				Image image = mImages.get(i);
				if (image.isSelected()) {
					mDeletedImages.add(image);
					mImages.remove(i);
				} else {
					i++;
				}
			}
			notifyDataSetChanged();
		}
		
		public void clearSelection() {
			for (Image img : mImages) {
				img.setSelected(false);
			}
			notifyDataSetChanged();
		}
		
		public boolean isItemSelected(int position) {
			return getItem(position).isSelected();
		}
		
		public void setItemSelected(int position, boolean selected) {
			getItem(position).setSelected(selected);
			notifyDataSetChanged();
		}

		public void selectAll() {
			for (Image img : mImages) {
				img.setSelected(true);
			}
			notifyDataSetChanged();
		}
		
		@Override
		public int getCount() {
			return mImages.size();
		}

		@Override
		public Image getItem(int position) {
			return mImages.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}
		
		public void add(Image image) {
			mImages.add(image);
			notifyDataSetChanged();
		}
		
		public void addAll(Collection<? extends Image> images) {
			mImages.addAll(images);
			notifyDataSetChanged();
		}
		
		@SuppressWarnings("deprecation")
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ImageView iv;
			if (convertView == null) {
				iv = new ImageView(mContext);
				iv.setLayoutParams(new GridView.LayoutParams(mMatchParent, mMatchParent));
				iv.setScaleType(ScaleType.CENTER_CROP);
			} else {
				iv = (ImageView) convertView;
			}
			if (iv.getLayoutParams().height != mItemSize) {
				iv.getLayoutParams().height = mItemSize;
			}
			Image image = getItem(position);
			if (mImageFetcher.loadImage(image.getPath(), iv)) {
				if (image.isSelected()) {
					iv.setBackgroundColor(Color.RED);
					iv.setAlpha(0x88);
				} else {
					iv.setBackgroundDrawable(null);
					iv.setAlpha(0xff);
				}
			}
			return iv;
		}

	}

}
